#include "Comproctol.hpp"
#include<iostream>
#include<fstream>

#define DEBUG

SocketClient* client = SocketClient::getInstance();
shared_ptr<map<HSocket, ComProtocol::UserList> > UserList(new map<HSocket, ComProtocol::UserList >);
bool ISLogin = false;
string UID;

template<typename T>
void pri(string Key, T Value, bool NewLine = true, int Tab = 0, int EndTab = 0)
{
	rep(i, 1, Tab * 4)
	{
		cout << " ";
	}
	cout << "[" << Key << "] " << Value;
	rep(i, 1, EndTab * 4)
	{
		cout << " ";
	}
	if (NewLine)cout << endl;
}

void PreConnect() {
	ifstream ifs("config.txt");
	string IP; unsigned short PORT;
	ifs >> PORT;
	ifs >> IP;
	client->connectServer(IP.c_str(), PORT, true, false);
}

void PreLogin() {
	string PWD;
	pri<string>("ID", "", false);
	cin >> UID;
	pri<string>("PWD", "", false);
	cin >> PWD;
	ComProtocol::Send::Login sed(UID, PWD);
	client->sendMessage(sed.Pack());
}

void Login(shared_ptr<DataStream> dm) {
	ComProtocol::Recv::Login rev(dm);
	ISLogin = rev.Return;
	pri<bool>("Return", rev.Return);
	if (rev.Return == false) {
		PreLogin();
	}
}

void GlobalMsg(shared_ptr<DataStream> dm) {
	ComProtocol::Recv::GlobalMsg rev(dm);
	pri<string>(rev.ID, rev.msg);
}

void GetList(shared_ptr<DataStream> dm) {
	ComProtocol::Recv::GetList ret(dm);
	UserList = ret.UserList_;
	pri<int>("Count", UserList->size());

	for (pair<HSocket, ComProtocol::UserList> var : *UserList)
	{
		pri<HSocket>(var.second.ID, var.second.User);
	}
}

void OperateSEND(string & msg) {
	switch (msg.at(0))
	{
	case '@': {
		string::iterator it = msg.begin() + 1;
		HSocket sig = 0;
		int tmp;
		while (it != msg.end() && *it!='|') {
			tmp = *it - '0';
			sig = (sig << 3) + (sig << 1) + tmp;
			it++;
		}
		it++;
		string m_="[Private] ";
		while (it < msg.end())m_ += *it, it++;
		ComProtocol::Recv::GlobalMsg se_(UID,m_);
		ComProtocol::Send::SendTo ss(se_.Pack(), sig);
		client->sendMessage(ss.Pack());
		break;
	}
	case ':': {
		switch (msg.at(1))
		{
		case 'l': {
			ComProtocol::Send::GetList sed;
			client->sendMessage(sed.Pack());
			break;
		}
		default:
			break;
		}
		break;
	}
	default: {
		ComProtocol::Send::GlobalMsg se_(msg);
		client->sendMessage(se_.Pack());
		break;
	}
	}
}

void OperateREV(shared_ptr<DataStream> dm) {
	ComProtocol::OperationType otype = ComProtocol::OperationType::Normal;
	dm->DoObj<ComProtocol::OperationType>(otype);
	switch (otype)
	{
	case ComProtocol::Normal:
		break;
	case ComProtocol::Login:
		Login(dm);
		break;
	case ComProtocol::GetList:
		GetList(dm);
		break;
	case ComProtocol::GetInfor:
		break;
	case ComProtocol::SendTo: {
		ComProtocol::Recv::SendTo rev(dm);
		OperateREV(rev.withstream);
		break;
	}
	case ComProtocol::GlobalMsg:
		GlobalMsg(dm);
		break;
	case ComProtocol::Quiet:
		break;
	default:
		break;
	}
}

int main() {

	client->onDisconnect = []() {

	};
	client->onError = [](ErrorCode ecode) {
		pri<int>("Error", ecode);
	};
	client->onConnect = []() {

	};
	client->onRecv = [](shared_ptr<DataStream> dm) {
		OperateREV(dm);
	};

	PreConnect();
	PreLogin();

	while (true)
	{
		while (!ISLogin)sleep(0.01f);
		string msg;
		cin >> msg;
		OperateSEND(msg);
	}

	getchar();

	return 0;
}
